// node服务器,处理浏览器加载各种资源的请求
// index.html
// js or ts
// vue

const koa = require("koa");
const fs = require("fs");
const path = require("path");

// single file component
const compilerSFC = require("@vue/compiler-sfc"); // vue自带
const compilerDOM = require("@vue/compiler-dom"); // vue自带

// 静态资源文件的服务
const app = new koa();

app.use(async (ctx) => {
    // context
  //console.log(ctx);
  const { url, query } = ctx.request;

  // 读取index.html文件
  if (url === "/") {
    ctx.type = "text/html";
    ctx.body = fs.readFileSync("src/index.html", "utf8");
      // console.log(fs.readFileSync("src/index.html", "utf8"))
  } else if (url.endsWith(".ts") || url.endsWith(".js")) {
    // 读取 .ts or .js
    const p = path.join(__dirname, `src/${url}`);

    ctx.type = "application/javascript";
    ctx.body = reWriteImport(fs.readFileSync(p, "utf8"));
      //console.log(fs.readFileSync(p, "utf8"))
  } else if (url.startsWith("/@modules/")) {
    //裸模块名称
    const moduleName = url.replace("/@modules/", "");

    //去node_modules目录中去找
    // 获取文件前缀 先获取node_modules的真实路径文件地址 在获取获取裸模块所在的文件件
    const prefix = path.join(__dirname, "/node_modules", moduleName);

    // console.log(prefix, "==");

    // 前缀地址
    // 从package.json中获取  获取vue 打包后的地址 要不然还都是裸模块
    const module = require(prefix + "/package.json").module;

    // 后缀地址
    const filePath = path.join(prefix, module);
      console.log(filePath, '======module')
    const file = fs.readFileSync(filePath, "utf8");

    ctx.type = "application/javascript";
    ctx.body = reWriteImport(file);
  } else if (url.includes(".vue")) {
    // 处理.vue的文件  解析成js
    const p = path.join(__dirname, `src/${url.split("?")[0]}`);
      console.log(p, '=====p')
    const ast = compilerSFC.parse(fs.readFileSync(p, "utf8"));
      console.log(ast, '=====ast')
    if (!query.type) {
      const scriptContent = ast.descriptor.script.content;
      const script = scriptContent.replace(
        "export default ",
        "const __script = "
      );

      // 生成sfc 加上参数template让它变成url 方便再次发送请求; 分两次请求并转换: 因为解析template需要另外一个方法  实际在vite中也是分两次请求解析
      ctx.type = "application/javascript";
      ctx.body = `
      ${reWriteImport(script)}
      import {render as __render} from '${url}?type=template'
      __script.render = __render
      export default __script
    `;
    } else if (query.type === "template") {
      const tpl = ast.descriptor.template.content;
      // 以模块的方式编译为 render 函数
      const render = compilerDOM.compile(tpl, { mode: "module" }).code;

        console.log(render, '----render')
      ctx.type = "application/javascript";
      ctx.body = reWriteImport(render);
    }
  }
});
//
/**
 * 工具函数 - 重写import 处理裸模块
 * */
function reWriteImport(content) {
  return content.replace(/ from ['"](.*)['"]/g, (str1, str2) => {
    // 如果包含这三个我们就认定它是相对地址 否则就是裸模块

    if (
      str2.startsWith("/") ||
      str2.startsWith("./") ||
      str2.startsWith("../")
    ) {
      return str1;
    } else {
      return ` from '/@modules/${str2}'`;
    }
  });
}

const port = 8088;

app.listen(port, () => {
  console.log("vite startup!!");
  console.log(`http://localhost:${port}`);
});
